package edu.washington.cs.cse461.project3;

import java.util.Properties;

import edu.uw.cs.cse461.sp12.OS.OS;
import edu.uw.cs.cse461.sp12.OS.RPCService;
import edu.uw.cs.cse461.sp12.OSConsoleApps.Echo;
import edu.uw.cs.cse461.sp12.OSConsoleApps.Ping;
import edu.uw.cs.cse461.sp12.util.Log;
import android.app.Activity;
import android.content.Context;
import android.content.SharedPreferences;
import android.graphics.Color;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.*;

public class RPCAndroidActivity extends Activity implements RadioGroup.OnCheckedChangeListener {
	public static final String TAG = "RPCAndroidActivity";
    public static final String PREFS_NAME = "CSE461";
    public static Context APP_CONTEXT = null;
    
	protected static final String[] RPCApps = {"edu.uw.cs.cse461.sp12.OSConsoleApps.Echo", 
		   										"edu.uw.cs.cse461.sp12.OSConsoleApps.WhoAmI",
		   										"edu.uw.cs.cse461.sp12.OSConsoleApps.Ping",
												};

	private String mServerHost;
    private int mServerPort;
    
    
    private RadioGroup radioAppGroup;
    private RadioButton radioAppButton;
    private Button btnStart;
    private EditText editTextHost;
    private EditText editTextPort;
    private EditText editTextMessage;
    private EditText editTextResult;
    
	/** Called when the activity is first created.  Establishes the UI.  Reads state information saved by previous runs. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        
        APP_CONTEXT = this.getApplicationContext();
        
        // Get reference to all editable text fields
        editTextHost = (EditText) findViewById(R.id.editTextHost);
        editTextPort = (EditText) findViewById(R.id.editTextPort);
        editTextMessage = (EditText) findViewById(R.id.editTextMessage);
        editTextResult = (EditText) findViewById(R.id.editTextResult);
        
        // Initially disable all editable text fields due to WhoAmI being
        //	the default application
    	editTextHost.setEnabled(false);
    	editTextPort.setEnabled(false);
    	editTextMessage.setEnabled(false);
    	editTextResult.setClickable(false);
        
        // Setup listener for group of radio buttons.
        //	If whoami is selected, all editTexts will be uneditable.
        //	If echo is selected, all editTexts will be editable.
        //	If ping is selected, all editTexts will be editable, except for Message
        radioAppGroup = (RadioGroup) findViewById(R.id.radioApplication);
        radioAppGroup.setOnCheckedChangeListener(this);
        
    	startServer();
    	
        addListenerOnStartButton();
    }
    
    
    public void onCheckedChanged(RadioGroup group, int checkedId) {
    	radioAppButton = (RadioButton) findViewById(checkedId);
    	
    	// Clear text and set it to success
    	editTextResult.setText("");
    	editTextResult.setTextColor(Color.BLUE);
    	
        if(radioAppButton.getText().equals("WhoAmI")) {
        	editTextHost.setEnabled(false);
        	editTextHost.setText("");
        	editTextPort.setEnabled(false);
        	editTextPort.setText("");
        	editTextMessage.setEnabled(false);
        	editTextMessage.setText("");
        } else if (radioAppButton.getText().equals("Echo")) {
        	editTextHost.setEnabled(true);
        	editTextPort.setEnabled(true);
        	editTextMessage.setEnabled(true);
        } else if (radioAppButton.getText().equals("Ping")) {
        	editTextHost.setEnabled(true);
        	editTextPort.setEnabled(true);
        	editTextMessage.setEnabled(false);
        	editTextMessage.setText("");
        }
    }

    
    
    public void addListenerOnStartButton() {    	 
    	btnStart = (Button) findViewById(R.id.btnStart);
    	btnStart.setOnClickListener(new OnClickListener() {
 
    		@Override
    		public void onClick(View v) {
    			radioAppButton = (RadioButton) findViewById(radioAppGroup.getCheckedRadioButtonId());

    	    	// Clear text and set it to success
    	    	editTextResult.setText("");
    	    	editTextResult.setTextColor(Color.BLUE);

    	    	try {
	    			if (radioAppButton.getText().equals("WhoAmI")) {
	    				// Just use the local server port
	    				RPCService server = (RPCService) OS.getService("rpc");
	    				String wifiIP = ((RPCService)OS.getService("rpc")).localIP();
	    				int port = server.localPort();
	    				
	    				editTextResult.setText("WhoAmI:\n\tIP: " + wifiIP + "\n\tPort: " + port);
	    			} else if (radioAppButton.getText().equals("Echo")) {
	    				
	    	        	String targetIP = editTextHost.getText().toString();
	    	        	
	    	        	String targetPort = editTextPort.getText().toString();
	    	        	String message = editTextMessage.getText().toString();
	    	        	String echoResult = Echo.performCall(targetIP, targetIP, targetPort, message);
	    	            editTextResult.setText("Echo Result: " + echoResult);
	    			} else if (radioAppButton.getText().equals("Ping")) {
	    				
	    				editTextResult.setText("Pinging " + editTextHost.getText().toString() + "...");
	    				
	    	        	String targetIP = editTextHost.getText().toString();
	    	        	String targetPort = editTextPort.getText().toString();
	    	        	
	    	        	int[] pingTimes = new int[5];
	    	        	
	    	        	for (int i = 0; i < pingTimes.length; i++){
							// Add duration to array of times
							pingTimes[i] = Ping.performCall(targetIP, targetIP, targetPort);
							
							// Output time for specific ping
							String text = editTextResult.getText().toString() + "\n\tPing " + (i + 1) + " time: " + pingTimes[i] + "ms";
							editTextResult.setText(text);
						}
	    	        	
	    	        	outputPingResults(pingTimes);
	    			}
    			} catch (Exception e) {
    	    		Log.e(TAG, "Exception: " + e.getMessage());
    				
    	    		// Set result to failure
        	    	editTextResult.setTextColor(Color.RED);
        	    	
        	    	String toastMessage = "ERROR: " + e.getMessage();
        	    	String errorMessage = toastMessage;
        	    	for (StackTraceElement ste : e.getStackTrace()) {
        	    		errorMessage += "\n\t" + ste.toString();
        	    	}
        	    	
        	    	editTextResult.setText(errorMessage);
        	    	
        	    	Toast toast = Toast.makeText(getApplicationContext(), toastMessage, Toast.LENGTH_LONG);
        	    	toast.show();
    			}
    		}
    		
    		
    		private void outputPingResults(int[] pingTimes){
    			if (pingTimes.length > 0){
    				int max = 0;
    				int min = 0; 
    				int sum = 0;
    				int avg;
    				
    				for (int i = 0; i < pingTimes.length; i++){
    					int time = pingTimes[i];
    					
    					if (i == 0){
    						max = time;
    						min = time;
    					} else {
    						max = Math.max(max, time);
    						min = Math.min(min, time);
    					}
    					sum += time;
    				}
    				
    				avg = sum / pingTimes.length;
    			
    				editTextResult.setText(editTextResult.getText().toString() + "\nMax Ping Time = " + max + "ms" +
    					"\nMin Ping Time = " + min + "ms" + "\nAvg Ping Time = " + avg + "ms");
    			}
    		}
    	});
    }
    
    
    
    
    
    private void startServer() {
    	try {
			String configFilename = "android.config.ini";
			Properties config = new Properties();
			config.load(getAssets().open(configFilename));

			String showDebug = config.getProperty("debug.enable");
			Log.setShowLog( showDebug == null || (!showDebug.isEmpty() && !showDebug.equals("0")) );
			String debugLevel = config.getProperty("debug.level");
			if ( debugLevel != null ) {
				try {
					Log.setLevel(Integer.parseInt(debugLevel));
				} catch (Exception e) {
					Log.e(TAG, "debug.level incorrect (Should be 0 or 1.)");
				}
			}
	
			// boot the OS and load RPC services
			OS.boot(config);
			OS.startServices(OS.rpcServiceClasses);
    	} catch (Exception e) {
    		Log.e(TAG, e.getMessage());
    	}
    }
    
    /**
     * Called when activity is stopped.  Save user preferences for next execution.
     */
    @Override
    protected void onStop() {
    	super.onStop();
    	
    	SharedPreferences settings = getSharedPreferences(PREFS_NAME, 0);
    	SharedPreferences.Editor editor = settings.edit();
    	editor.putString("serverhost", mServerHost);
    	editor.putInt("serverport", mServerPort);
    	editor.commit();
    }   
}